﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class UpdateRes : MonoBehaviour
{
    /// <summary>
    /// 总下载进度
    /// </summary>
    public Slider allFileslider;
    /// <summary>
    /// 当前文件下载进度
    /// </summary>
    public Slider nowFileslider;

    public Text t1;
    public Text t2;
    public Text t3;
    public Text t4;

    /// <summary>
    /// 资源服务器地址
    /// </summary>
    string serverRoot = "https://xuefei.net.cn/HybridCLR/";
    /// <summary>
    /// 服务器端版本文件地址
    /// </summary>
    string serverVerUrl;
    string serverABUrl;
    /// <summary>
    /// 本地ab文件存放路径
    /// </summary>
    static string abPath;

    /// <summary>
    /// 更新文件的队列
    /// </summary>
    Queue<ResFile> upContent = new Queue<ResFile>();

    /// <summary>
    /// 已经下载好的数量
    /// </summary>
    private int readyCount = 0;
    /// <summary>
    /// 总数量
    /// </summary>
    private int allCount = 0;
    /// <summary>
    /// 总进度
    /// </summary>
    private float allProgress;
    /// <summary>
    /// 当前文件的下载进度
    /// </summary>
    private float nowProgress;

    public GameObject logic;

    public void Init(int ResVer)
    {
        serverABUrl = serverRoot + ResVer
            + "/" + Util.GetPlatformName(Application.platform) + "/";
        serverVerUrl = serverABUrl + "version.txt";
        abPath = Application.persistentDataPath + "/Res/";
        if (!Directory.Exists(abPath))
        {
            Directory.CreateDirectory(abPath);
        }
        allFileslider = transform.Find("Slider1").GetComponent<Slider>();
        nowFileslider = transform.Find("Slider2").GetComponent<Slider>();

        t1 = transform.Find("t1").GetComponent<Text>();
        t2 = transform.Find("t2").GetComponent<Text>();
        t3 = transform.Find("t3").GetComponent<Text>();
        t4 = transform.Find("t4").GetComponent<Text>();
        StartCoroutine(DownLoadVersion());
    }

    bool isStart = false;
    bool isRun = false;

    // Update is called once per frame
    void Update()
    {
        if (isStart)
        {
            t1.text = "所有文件下载进度：" + allProgress;
            t2.text = "当前文件下载进度：" + nowProgress;
            t3.text = "已下载文件数：" + readyCount;
            t3.text = "未下载文件数：" + upContent.Count;

            allFileslider.value = allProgress;
            nowFileslider.value = nowProgress;
        }
        if (isStart && !isRun && upContent.Count > 0)
        {
            Debug.Log("未下载文件数：" + upContent.Count);
            isRun = true;
            ResFile content = upContent.Dequeue();
            StartCoroutine(DownFile(content));
        }
    }

    void StartDownLoad()
    {
        isStart = true;
    }

    /// <summary>
    /// 服务器端版本信息
    /// </summary>
    ResVersion serverVerInfo;

    /// <summary>
    /// 下载服务器端资源版本信息
    /// </summary>
    /// <returns></returns>
    IEnumerator DownLoadVersion()
    {
        Debug.Log("serverVerUrl:" + serverVerUrl);
        UnityWebRequest uwr = UnityWebRequest.Get(serverVerUrl);
        yield return uwr.SendWebRequest();
        if (File.Exists(abPath + "version-new.txt"))
        {
            File.Delete(abPath + "version-new.txt");
        }
        FileStream fs = new FileStream(abPath + "version-new.txt", FileMode.Create);
        //获得字节数组
        byte[] data = System.Text.Encoding.Default.GetBytes(uwr.downloadHandler.text);
        //开始写入
        fs.Write(data, 0, data.Length);
        //清空缓冲区、关闭流
        fs.Flush();
        fs.Close();

        serverVerInfo = ReadMD5File(abPath + "version-new.txt");

        //本地有版本文件
        if (File.Exists(abPath + "version.txt"))
        {
            ResVersion localVerInfo = ReadMD5File(abPath + "version.txt");
            ResVersion upInfo = GetUpInfo(serverVerInfo, localVerInfo);

            for (int i = 0; i < upInfo.resFiles.Count; i++)
            {
                ResFile content = new ResFile();
                content.name = upInfo.resFiles[i].name;
                content.md5 = upInfo.resFiles[i].md5;
                upContent.Enqueue(content);
            }
        }
        //本地没有版本文件
        else
        {
            for (int i = 0; i < serverVerInfo.resFiles.Count; i++)
            {
                ResFile content = new ResFile();
                content.name = serverVerInfo.resFiles[i].name;
                content.md5 = serverVerInfo.resFiles[i].md5;
                upContent.Enqueue(content);
            }
        }

        if (upContent.Count > 0)
        {
            allCount = upContent.Count;
            StartDownLoad();
        }
        else
        {

            UpdateComplete();
        }
    }

    /// <summary>
    /// 下载文件
    /// </summary>
    /// <param name="resFile"></param>
    /// <returns></returns>
    IEnumerator DownFile(ResFile resFile)
    {
        string fileUrl = serverABUrl + resFile.name;
        Debug.Log("文件url：" + fileUrl);
        UnityWebRequest headRequest = UnityWebRequest.Head(fileUrl);
        yield return headRequest.SendWebRequest();
        //网络文件长度
        var totalLength = long.Parse(headRequest.GetResponseHeader("Content-Length"));
        Debug.Log("网络文件长度:" + totalLength);
        var fs = new FileStream(abPath + resFile.name, FileMode.OpenOrCreate, FileAccess.Write);
        //本地文件长度
        var localLength = fs.Length;
        Debug.Log("本地文件长度:" + localLength);
        if (localLength < totalLength)
        {
            fs.Seek(localLength, SeekOrigin.Begin);

            var request = UnityWebRequest.Get(fileUrl);
            request.SetRequestHeader("Range", "bytes=" + localLength + "-");

            yield return request.SendWebRequest();
            Debug.Log("返回信息：" + request.responseCode + ":" + request.error);

            if (string.IsNullOrEmpty(request.error) && (request.responseCode == 200 || request.responseCode == 206))
            {
                var index = 0;
                bool state = true;
                while (state)
                {
                    var buff = request.downloadHandler.data;
                    if (buff != null)
                    {
                        var length = buff.Length - index;
                        fs.Write(buff, index, length);
                        index += length;
                        localLength += length;

                        nowProgress = localLength / (float)totalLength;

                        Debug.Log("nowProgress:" + nowProgress);
                        if (localLength == totalLength)
                        {
                            fs.Close();
                            fs.Dispose();

                            nowProgress = 1f;

                            CheckeFile(resFile);
                            state = false;
                        }
                    }
                }
            }
            else
            {
                upContent.Enqueue(resFile);
                Debug.Log("下载出错：" + request.responseCode + ":" + request.error);
                fs.Close();
                fs.Dispose();
                isRun = false;
            }

        }
        else
        {
            fs.Close();
            fs.Dispose();

            nowProgress = 1f;

            CheckeFile(resFile);
        }
    }

    /// <summary>
    /// 检查文件完整性
    /// </summary>
    void CheckeFile(ResFile content)
    {
        if (File.Exists(abPath + content.name))
        {
            if (Util.GetFileMD5(abPath + content.name) == content.md5)
            {
                Debug.Log("已下载并通过校验：" + abPath + content.name);
                readyCount += 1;
                allProgress = (float)((float)readyCount / (float)allCount);

                if (upContent.Count < 1)
                {
                    Debug.Log("更新完成！");
                    UpdateComplete();
                }
            }
            else
            {
                File.Delete(abPath + content.name);
                Debug.Log("校验失败删除重新加入下载队列：" + abPath + content.name);
                upContent.Enqueue(content);
            }
        }
        else
        {
            Debug.Log("校验失败删除重新加入下载队列：" + abPath + content.name);
            upContent.Enqueue(content);
        }
        isRun = false;
    }

    /// <summary>
    /// 完成更新
    /// </summary>
    void UpdateComplete()
    {
        //本地有版本文件
        if (File.Exists(abPath + "version.txt"))
        {
            File.Delete(abPath + "version.txt");
        }
        File.Move(abPath + "version-new.txt", abPath + "version.txt");
        isStart = false;
        //更新完成
        Debug.Log("更新完成");
        logic.SetActive(true);
        gameObject.SetActive(false);
    }

    /// <summary>
    /// 比较版本信息
    /// </summary>
    /// <param name="serVer"></param>
    /// <param name="localVer"></param>
    /// <returns></returns>
    public ResVersion GetUpInfo(ResVersion serVer, ResVersion localVer)
    {
        ResVersion upInfo = new ResVersion();
        upInfo.resFiles = new List<ResFile>();
        foreach (ResFile content in serVer.resFiles)
        {
            if (!File.Exists(abPath + content.name))
            {
                Debug.Log("本地缺少文件：" + abPath + content.name);
                upInfo.resFiles.Add(content);
            }
            else
            {
                if (Util.GetFileMD5(abPath + content.name) != content.md5)
                {
                    Debug.Log("本地文件md5和服务器不一致：" + abPath + content.name);
                    upInfo.resFiles.Add(content);
                }
            }
        }
        return upInfo;
    }

    public static ResVersion ReadMD5File(string fileName)
    {
        ResVersion versionInfo = new ResVersion();
        versionInfo.resFiles = new List<ResFile>();
        try
        {
            // 如果文件不存在，则直接返回
            if (File.Exists(fileName) == false)
            {
                return versionInfo;
            }
            StreamReader sr = new StreamReader(fileName);
            string fileListString = sr.ReadToEnd();
            sr.Close();
            JsonUtility.FromJsonOverwrite(fileListString, versionInfo);
        }
        catch (Exception e)
        {
            Debug.LogError(e.ToString());
        }
        return versionInfo;
    }
}